	PAGE	80,132 ;
	TITLE	DEBASM.ASM
; CODE FOR THE ASSEMBLE COMMAND IN THE DEBUGGER

	IF1
	    %OUT COMPONENT=DEBUG, MODULE=DEBASM
	ENDIF
.XLIST
.XCREF
	INCLUDE DOSSYM.INC
	INCLUDE DEBEQU.ASM
.CREF
.LIST


CODE	SEGMENT PUBLIC BYTE
CODE	ENDS

CONST	SEGMENT PUBLIC BYTE

	EXTRN	DBMN:BYTE,CSSAVE:WORD,REG8:BYTE,REG16:BYTE,SIZ8:BYTE
	EXTRN	SYNERR_PTR:BYTE,OPTAB:BYTE,MAXOP:ABS

CONST	ENDS

CSTACK	SEGMENT STACK
CSTACK	ENDS

DATA	SEGMENT PUBLIC BYTE

	EXTRN	HINUM:WORD,LOWNUM:WORD,ASSEM_CNT:BYTE
	EXTRN	ASSEM1:BYTE,ASSEM2:BYTE,ASSEM3:BYTE,ASSEM4:BYTE,ASSEM5:BYTE
	EXTRN	ASSEM6:BYTE,OPBUF:BYTE,OPCODE:WORD,REGMEM:BYTE,INDEX:WORD
	EXTRN	ASMADD:BYTE,ASMSP:WORD,MOVFLG:BYTE,SEGFLG:BYTE,TSTFLG:BYTE
	EXTRN	NUMFLG:BYTE,DIRFLG:BYTE,BYTEBUF:BYTE,F8087:BYTE,DIFLG:BYTE
	EXTRN	SIFLG:BYTE,BXFLG:BYTE,BPFLG:BYTE,NEGFLG:BYTE,MEMFLG:BYTE
	EXTRN	REGFLG:BYTE,AWORD:BYTE,MIDFLD:BYTE,MODE:BYTE
	EXTRN	ARG_BUF:BYTE,HEX_PTR:BYTE

DATA	ENDS

DG	GROUP	CODE,CONST,CSTACK,DATA

CODE	SEGMENT PUBLIC BYTE
ASSUME	CS:DG,DS:DG,ES:DG,SS:DG

	PUBLIC	ASSEM
	PUBLIC	DB_OPER,DW_OPER,ASSEMLOOP,GROUP2,AA_OPER,DCINC_OPER
	PUBLIC	GROUP1,ESC_OPER,FGROUPP,FGROUPX,FDE_OPER,FGROUPZ
	PUBLIC	FD9_OPER,FGROUP,FDB_OPER,FGROUPB,FGROUP3,FGROUP3W
	PUBLIC	FGROUPDS,INT_OPER,IN_OPER,DISP8_OPER,JMP_OPER,NO_OPER
	PUBLIC	OUT_OPER,L_OPER,MOV_OPER,POP_OPER,PUSH_OPER,ROTOP
	PUBLIC	TST_OPER,EX_OPER,GET_DATA16,CALL_OPER, DOORG

	EXTRN	INBUF:NEAR,SCANB:NEAR,SCANP:NEAR,GETHX:NEAR,GET_ADDRESS:NEAR
	EXTRN	DEFAULT:NEAR,OUTDI:NEAR,BLANK:NEAR,TAB:NEAR
	EXTRN	STD_PRINTF:NEAR,PRINTF_CRLF:NEAR

;	Line by line assembler

MASKMOD EQU	11000000B
SHMOD	EQU	6
MASKREG EQU	00111000B
SHREG	EQU	3
MASKRM	EQU	00000111B
SHRM	EQU	0

ASSEM:
	MOV	BP,[CSSAVE]		; Default code segment
	MOV	DI,OFFSET DG:ASMADD	; Default address
	CALL	DEFAULT
	MOV	WORD PTR [ASMADD],DX	; Displacement of disassembly
	MOV	WORD PTR [ASMADD+2],AX	; Segment
	MOV	[ASMSP],SP		; Save sp in case of error

ASSEMLOOP:
	MOV	SP,[ASMSP]		; Restore sp in case of error
	LES	DI,DWORD PTR ASMADD	; GET PC
	CALL	OUTDI			; OUTPUT ADDRESS
	PUSH	CS
	POP	ES
	PUSH	DI
	MOV	DI,OFFSET DG:ARG_BUF
; No spacing is needed.  The format string already has one.
;	CALL	BLANK			; SKIP A SPACE
	XOR	AL,AL
	STOSB
	MOV	DX,OFFSET DG:HEX_PTR
	CALL	STD_PRINTF
	POP	DI
	CALL	INBUF			; GET A BUFFER
	CALL	SCANB
	JNZ	OPLOOK
	RET				; if empty just return

;  At this point ds:si points to the opcode mnemonic...
OPLOOK:
	XOR	CX,CX			; OP-CODE COUNT = 0
	MOV	DI,OFFSET DG:DBMN
OPSCAN:
	XOR	BX,BX
OPLOOP:
	MOV	AL,[DI+BX]
	CMP	AL,[SI+BX]
	JZ	OPMATCH
	INC	CX			; INCREMENT OP-CODE COUNT
	CMP	CX,MAXOP		; CHECK FOR END OF LIST
	JB	OP1
	JMP	ASMERR
OP1:
	INC	DI			; SCAN FOR NEXT OP-CODE...
	CMP	BYTE PTR [DI-1],0
	JNZ	OP1
	JMP	OPSCAN

OPMATCH:
	INC	BX			; COMPARE NEXT CHAR
	CMP	BYTE PTR [DI+BX],0	; ARE WE DONE?
	JNZ	OPLOOP			; ..IF NOT KEEP COMPARING
	XCHG	BX,CX
	MOV	AX,BX
	SHL	AX,1
	ADD	AX,BX
	ADD	AX,OFFSET DG:OPTAB
	MOV	BX,AX

; CX = COUNT OF CHARS IN OPCODE
; BX = POINTER INTO OPCODE TABLE

	XOR	AX,AX
	MOV	BYTE PTR [AWORD],AL
	MOV	WORD PTR [MOVFLG],AX	; MOVFLG + TSTFLG
	MOV	BYTE PTR [SEGFLG],AL	; ZERO SEGMENT REGISTER FLAG
	MOV	AH,00001010B		; SET UP FOR AA_OPER
	MOV	AL,BYTE PTR [BX]
	MOV	WORD PTR [ASSEM1],AX
	MOV	BYTE PTR [ASSEM_CNT],1

	ADD	SI,CX			; SI POINTS TO OPERAND
	JMP	WORD PTR [BX+1]

; 8087 INSTRUCTIONS WITH NO OPERANDS

FDE_OPER:
	MOV	AH,0DEH
	JMP	SHORT FDX_OPER
FDB_OPER:
	MOV	AH,0DBH
	JMP	SHORT FDX_OPER
FD9_OPER:
	MOV	AH,0D9H
FDX_OPER:
	XCHG	AL,AH
	MOV	WORD PTR [ASSEM1],AX

;  AAD AND AAM INSTRUCIONS

AA_OPER:
	INC	BYTE PTR [ASSEM_CNT]

;  INSTRUCTIONS WITH NO OPERANDS

NO_OPER:
	CALL	STUFF_BYTES
	CALL	SCANP
	PUSH	CS
	POP	ES
	JNZ	OPLOOK
	JMP	ASSEMLOOP

;  PUSH INSTRUCTION

PUSH_OPER:
	MOV	AH,11111111B
	JMP	SHORT POP1

;  POP INSTRUCTION

POP_OPER:
	MOV	AH,10001111B
POP1:
	MOV	[ASSEM1],AH
	MOV	[MIDFLD],AL
	INC	BYTE PTR [MOVFLG]	; ALLOW SEGMENT REGISTERS
	MOV	BYTE PTR [AWORD],2	; MUST BE 16 BITS
	CALL	GETREGMEM
	CALL	BUILDIT
	MOV	AL,[DI+2]
	CMP	AL,11000000B
	JB	DATRET
	MOV	BYTE PTR [DI],1
	CMP	BYTE PTR [MOVFLG],2
	JNZ	POP2
	AND	AL,00011000B
	OR	AL,00000110B
	CMP	BYTE PTR [MIDFLD],0
	JNZ	POP3
	OR	AL,00000001B
	JMP	SHORT POP3

POP2:
	AND	AL,MASKRM
	OR	AL,01010000B
	CMP	BYTE PTR [MIDFLD],0
	JNZ	POP3
	OR	AL,01011000B
POP3:
	MOV	BYTE PTR [DI+1],AL
	JMP	ASSEM_EXIT

; RET AND RETF INSTRUCTIONS

GET_DATA16:
	CALL	SCANB
	MOV	CX,4
	CALL	GETHX
	JC	DATRET
	DEC	BYTE PTR [ASSEM1]	; CHANGE OP-CODE
	ADD	BYTE PTR [ASSEM_CNT],2	; UPDATE LENGTH
	MOV	WORD PTR [ASSEM2],DX	; SAVE OFFSET
DATRET:
	JMP	ASSEM_EXIT


;  INT INSTRUCTION

INT_OPER:
	CALL	SCANB
	MOV	CX,2
	CALL	GETHX
	JC	ERRV1
	MOV	AL,DL
	CMP	AL,3
	JZ	DATRET
	INC	BYTE PTR [ASSEM1]
	JMP	DISPX

;  IN INSTRUCTION

IN_OPER:
	CALL	SCANB
	LODSW
	CMP	AX,'A'+4C00H            ; "AL"
	JZ	IN_1
	CMP	AX,'A'+5800H            ; "AX"
	JZ	IN_0
ERRV1:
	JMP	ASMERR
IN_0:
	INC	BYTE PTR [ASSEM1]
IN_1:
	CALL	SCANP
	CMP	WORD PTR [SI],'D'+5800H ; "DX"
	JZ	DATRET
	MOV	CX,2
	CALL	GETHX
	JC	ERRV1
	AND	BYTE PTR [ASSEM1],11110111B
	MOV	AL,DL
	JMP	DISPX

;  OUT INSTRUCTION

OUT_OPER:
	CALL	SCANB
	CMP	WORD PTR [SI],'D'+5800H ; "DX"
	JNZ	OUT_0
	INC	SI
	INC	SI
	JMP	SHORT OUT_1
OUT_0:
	AND	BYTE PTR [ASSEM1],11110111B
	MOV	CX,2
	CALL	GETHX
	JC	ERRV1
	INC	BYTE PTR [ASSEM_CNT]
	MOV	BYTE PTR [ASSEM2],DL
OUT_1:
	CALL	SCANP
	LODSW
	CMP	AX,'A'+4C00H            ; "AL"
	JZ	DATRET
	CMP	AX,'A'+5800H            ; "AX"
	JNZ	ERRV1
	INC	BYTE PTR [ASSEM1]
	JMP	DATRET


;  JUMP INSTRUCTION

JMP_OPER:
	INC	BYTE PTR [TSTFLG]

;  CALL INSTRUCTION

CALL_OPER:
	MOV	BYTE PTR [ASSEM1],11111111B
	MOV	BYTE PTR [MIDFLD],AL
	CALL	GETREGMEM
	CALL	BUILD3
	CMP	BYTE PTR [MEMFLG],0
	JNZ	CALLJ1
	CMP	BYTE PTR [REGMEM],-1
	JZ	CALLJ2

;  INDIRECT JUMPS OR CALLS

CALLJ1:
	CMP	BYTE PTR [AWORD],1
ERRZ4:
	JZ	ERRV1
	CMP	BYTE PTR [AWORD],4
	JNZ	ASMEX4
	OR	BYTE PTR [DI+2],1000B
	JMP	SHORT ASMEX4

;   DIRECT JUMPS OR CALLS

CALLJ2:
	MOV	AX,[LOWNUM]
	MOV	DX,[HINUM]
	MOV	BL,[AWORD]
	CMP	BYTE PTR [NUMFLG],0
	JZ	ERRZ4

;  BL = NUMBER OF BYTES IN JUMP
;  DX = OFFSET
;  AX = SEGMENT

CALLJ3:
	MOV	BYTE PTR [DI],5
	MOV	[DI+2],AX
	MOV	[DI+4],DX

	MOV	AL,10011010B		; SET UP INTER SEGMENT CALL
	CMP	BYTE PTR [TSTFLG],0
	JZ	CALLJ5
	MOV	AL,11101010B		; FIX UP FOR JUMP
CALLJ5:
	MOV	BYTE PTR [DI+1],AL
	CMP	BL,4			; FAR SPECIFIED?
	JZ	ASMEX4
	OR	BL,BL
	JNZ	CALLJ6
	CMP	DX,WORD PTR [ASMADD+2]	; DIFFERENT SEGMENT?
	JNZ	ASMEX4

CALLJ6:
	MOV	BYTE PTR [DI],3
	MOV	AL,11101000B		; SET UP FOR INTRASEGMENT
	OR	AL,[TSTFLG]
	MOV	BYTE PTR [DI+1],AL

	MOV	AX,[LOWNUM]
	SUB	AX,WORD PTR [ASMADD]
	SUB	AX,3
	MOV	[DI+2],AX
	CMP	BYTE PTR [TSTFLG],0
	JZ	ASMEX4
	CMP	BL,2
	JZ	ASMEX4

	INC	AX
	MOV	CX,AX
	CBW
	CMP	AX,CX
	JNZ	ASMEX3
	MOV	BYTE PTR [DI+1],11101011B
	MOV	[DI+2],AX
	DEC	BYTE PTR [DI]
ASMEX4:
	JMP	ASSEM_EXIT

;  CONDITIONAL JUMPS AND LOOP INSTRUCTIONS

DISP8_OPER:
	MOV	BP,WORD PTR [ASMADD+2]	; GET DEFAULT DISPLACEMENT
	CALL	GET_ADDRESS
	SUB	DX,WORD PTR [ASMADD]
	DEC	DX
	DEC	DX
	CALL	CHKSIZ
	CMP	CL,1
	JNZ	ERRV2
DISPX:
	INC	[ASSEM_CNT]
	MOV	BYTE PTR [ASSEM2],AL
ASMEX3:
	JMP	ASSEM_EXIT

;  LDS, LES, AND LEA INSTRUCTIONS

L_OPER:
	CALL	SCANB
	LODSW
	MOV	CX,8
	MOV	DI,OFFSET DG:REG16
	CALL	CHKREG
	JZ	ERRV2			; CX = 0 MEANS NO REGISTER
	SHL	AL,1
	SHL	AL,1
	SHL	AL,1
	MOV	BYTE PTR [MIDFLD],AL
	CALL	SCANP
	CALL	GETREGMEM
	CMP	BYTE PTR [AWORD],0
	JNZ	ERRV2
	CALL	BUILD2
	JMP	SHORT ASEXV

;  DEC AND INC INSTRUCTIONS

DCINC_OPER:
	MOV	BYTE PTR [ASSEM1],11111110B
	MOV	BYTE PTR [MIDFLD],AL
	CALL	GETREGMEM
	CALL	BUILDIT
	TEST	BYTE PTR [DI+1],1
	JZ	ASEXV
	MOV	AL,[DI+2]
	CMP	AL,MASKMOD
	JB	ASEXV
	AND	AL,1111B
	OR	AL,01000000B
	MOV	[DI+1],AL
	DEC	BYTE PTR [DI]
ASEXV:
	JMP	ASSEM_EXIT

ERRV2:
	JMP	ASMERR

; ESC INSTRUCTION

ESC_OPER:
	INC	BYTE PTR [AWORD]
	CALL	SCANB
	MOV	CX,2
	CALL	GETHX
	CMP	DX,64
	JAE	ERRV2
	CALL	SCANP
	MOV	AX,DX
	MOV	CL,3
	SHR	DX,CL
	OR	[ASSEM1],DL
	AND	AL,111B
	SHL	AL,CL
	JMP	GROUPE

; 8087 ARITHMETIC INSTUCTIONS

;  OPERANDS THAT ALLOW THE REVERSE BIT

FGROUPDS:
	CALL	SETMID
	CALL	GETREGMEM2
	CALL	BUILD3
	CMP	BYTE PTR [MODE],11000000B
	JNZ	FGROUP1
	MOV	AL,[DIRFLG]
	OR	AL,AL
	JZ	FEXIT
	OR	[DI+1],AL		; IF D=1...
	XOR	BYTE PTR [DI+2],00001000B ; ...REVERSE THE SENSE OF R
	JMP	SHORT FEXIT

;  HERE WHEN INSTRUCTION COULD HAVE MEMORY OR REGISTER OPERAND

FGROUPX:
	CALL	SETMID			; THIS ENTRY POINT FOR 1 MEM OPER
	MOV	BYTE PTR [DIRFLG],0
	JMP	SHORT FGRP2
FGROUP:
	CALL	SETMID
FGRP2:
	CALL	GETREGMEM2
	CALL	BUILD3
	CMP	BYTE PTR [MODE],11000000B
	JNZ	FGROUP1
	MOV	AL,[DIRFLG]
	OR	[DI+1],AL
	JMP	SHORT FEXIT
FGROUP1:
	CALL	SETMF
FEXIT:
	JMP	ASSEM_EXIT

; THESE 8087 INSTRUCTIONS REQUIRE A MEMORY OPERAND
FGROUPB:
	MOV	AH,5			; MUST BE TBYTE
	JMP	SHORT FGROUP3E
FGROUP3W:
	MOV	AH,2			; MUST BE WORD
	JMP	SHORT FGROUP3E
FGROUP3:
	MOV	AH,-1			; SIZE CANNOT BE SPECIFIED
FGROUP3E:
	MOV	[AWORD],AH
	CALL	SETMID
	CALL	GETREGMEM
	CMP	BYTE PTR [MODE],11000000B
	JZ	FGRPERR
FGRP:
	CALL	BUILD3
	JMP	FEXIT

; THESE 8087 INSTRUCTIONS REQUIRE A REGISTER OPERAND
FGROUPP:				; 8087 POP OPERANDS
	MOV	BYTE PTR [AWORD],-1
	CALL	SETMID
	CALL	GETREGMEM2
	CMP	BYTE PTR [DIRFLG],0
	JNZ	FGRP
FGRPERR:
	JMP	ASMERR

FGROUPZ:				; ENTRY POINT WHERE ARG MUST BE MEM
	CALL	SETMID
	MOV	BYTE PTR [DIRFLG],0
	CALL	GETREGMEM
	CMP	BYTE PTR [MODE],11000000B
	JZ	FGRPERR
	CALL	BUILD3
	CALL	SETMF
	JMP	FEXIT

; NOT, NEG, MUL, IMUL, DIV, AND IDIV INSTRUCTIONS

GROUP1:
	MOV	[ASSEM1],11110110B
GROUPE:
	MOV	BYTE PTR [MIDFLD],AL
	CALL	GETREGMEM
	CALL	BUILDIT
	JMP	FEXIT

;  SHIFT AND ROTATE INSTRUCTIONS

ROTOP:
	MOV	[ASSEM1],11010000B
	MOV	BYTE PTR [MIDFLD],AL
	CALL	GETREGMEM
	CALL	BUILDIT
	CALL	SCANP
	CMP	BYTE PTR [SI],'1'
	JZ	ASMEXV1
	CMP	WORD PTR [SI],"LC"      ; CL
	JZ	ROTOP1
ROTERR:
	JMP	ASMERR
ROTOP1:
	OR	BYTE PTR [ASSEM1],10B
ASMEXV1:
	JMP	ASSEM_EXIT

;  XCHG INSTRUCTION

EX_OPER:
	INC	BYTE PTR [TSTFLG]

;   TEST INSTRUCTION

TST_OPER:
	INC	BYTE PTR [TSTFLG]
	JMP	SHORT MOVOP

;    MOV INSTRUCTION

MOV_OPER:
	INC	BYTE PTR [MOVFLG]
MOVOP:
	XOR	AX,AX
	JMP	SHORT GROUPM

;   ADD, ADC, SUB, SBB, CMP, AND, OR, XOR instructions

GROUP2:
	MOV	BYTE PTR [ASSEM1],10000000B
GROUPM:
	MOV	BYTE PTR [MIDFLD],AL

	PUSH	AX
	CALL	GETREGMEM
	CALL	BUILD2
	CALL	SCANP			; POINT TO NEXT OPERAND
	MOV	AL,BYTE PTR [ASSEM_CNT]
	PUSH	AX
	CALL	GETREGMEM
	POP	AX
	MOV	BYTE PTR [DI],AL
	POP	AX
	MOV	BL,BYTE PTR [AWORD]
	OR	BL,BL
	JZ	ERRV5
	DEC	BL
	AND	BL,1
	OR	BYTE PTR [DI+1],BL

	CMP	BYTE PTR [MEMFLG],0
	JNZ	G21V
	CMP	BYTE PTR [NUMFLG],0	; TEST FOR IMMEDIATE DATA
	JZ	G21V
	CMP	BYTE PTR [SEGFLG],0
	JNZ	ERRV5
	CMP	BYTE PTR [TSTFLG],2	; XCHG?
	JNZ	IMMED1
ERRV5:
	JMP	ASMERR
G21V:
	JMP	GRP21

;  SECOND OPERAND WAS IMMEDIATE

IMMED1:
	MOV	AL,BYTE PTR [DI+2]
	CMP	BYTE PTR [MOVFLG],0
	JZ	NOTMOV1
	AND	AL,11000000B
	CMP	AL,11000000B
	JNZ	GRP23			; not to a register
					; MOVE IMMEDIATE TO REGISTER
	MOV	AL,BYTE PTR [DI+1]
	AND	AL,1			; SET SIZE
	PUSHF
	SHL	AL,1
	SHL	AL,1
	SHL	AL,1
	OR	AL,BYTE PTR [DI+2]	; SET REGISTER
	AND	AL,00001111B
	OR	AL,10110000B
	MOV	BYTE PTR [DI+1],AL
	MOV	AX,WORD PTR [LOWNUM]
	MOV	WORD PTR [DI+2],AX
	POPF
	JZ	EXVEC
	INC	BYTE PTR [DI]
EXVEC:
	JMP	GRPEX

NOTMOV1:
	AND	AL,11000111B
	CMP	AL,11000000B
	JZ	IMMACC			; IMMEDIATE TO ACC

	CMP	BYTE PTR [TSTFLG],0
	JNZ	GRP23
	CMP	BYTE PTR [MIDFLD],1*8	; OR?
	JZ	GRP23
	CMP	BYTE PTR [MIDFLD],4*8	; AND?
	JZ	GRP23
	CMP	BYTE PTR [MIDFLD],6*8	; XOR?
	JZ	GRP23
	TEST	BYTE PTR [DI+1],1	; TEST IF BYTE OPCODE
	JZ	GRP23

	MOV	AX,[LOWNUM]
	MOV	BX,AX
	CBW
	CMP	AX,BX
	JNZ	GRP23			; SMALL ENOUGH?

	MOV	BL,[DI]
	DEC	BYTE PTR [DI]
	OR	BYTE PTR [DI+1],10B
	JMP	SHORT GRP23X

IMMACC:
	MOV	AL,BYTE PTR [DI+1]
	AND	AL,1
	CMP	BYTE PTR [TSTFLG],0
	JZ	NOTTST
	OR	AL,10101000B
	JMP	SHORT TEST1
NOTTST:
	OR	AL,BYTE PTR [MIDFLD]
	OR	AL,100B
TEST1:
	MOV	BYTE PTR [DI+1],AL
	DEC	BYTE PTR [DI]

GRP23:
	MOV	BL,BYTE PTR [DI]
GRP23X:
	XOR	BH,BH
	ADD	BX,DI
	INC	BX
	MOV	AX,WORD PTR [LOWNUM]
	MOV	WORD PTR [BX],AX
	INC	BYTE PTR [DI]
	TEST	BYTE PTR [DI+1],1
	JZ	GRPEX1
	INC	BYTE PTR [DI]
GRPEX1:
	JMP	GRPEX

;	SECOND OPERAND WAS MEMORY OR REGISTER

GRP21:
	CMP	BYTE PTR [SEGFLG],0
	JZ	GRP28			; FIRST OPERAND WAS A SEGMENT REG
	MOV	AL,BYTE PTR [REGMEM]
	TEST	AL,10000B
	JZ	NOTSEG1
ERRV3:
	JMP	ASMERR
NOTSEG1:
	AND	AL,111B
	OR	BYTE PTR [DI+2],AL
	AND	BYTE PTR [DI+1],11111110B
	CMP	BYTE PTR [MEMFLG],0
	JNZ	G22V
	JMP	GRPEX

GRP28:
	AND	BYTE PTR [DI+2],11000111B
	MOV	AL,BYTE PTR [DI+1]	; GET FIRST OPCODE
	AND	AL,1B
	CMP	BYTE PTR [MOVFLG],0
	JZ	NOTMOV2
	OR	AL,10001000B
	JMP	SHORT MOV1
NOTMOV2:
	CMP	BYTE PTR [TSTFLG],0
	JZ	NOTTST2
	OR	AL,10000100B
	CMP	BYTE PTR [TSTFLG],2
	JNZ	NOTTST2
	OR	AL,10B
NOTTST2:
	OR	AL,BYTE PTR [MIDFLD]	; MIDFLD IS ZERO FOR TST
MOV1:
	MOV	BYTE PTR [DI+1],AL
	CMP	BYTE PTR [MEMFLG],0
G22V:
	JZ	NotGRP22
	JMP	GRP22
NotGRP22:

;	SECOND OPERAND WAS A REGISTER

	MOV	AL,BYTE PTR [REGMEM]
	TEST	AL,10000B		; SEGMENT REGISTER?
	JZ	NOTSEG
	CMP	BYTE PTR [MOVFLG],0
	JZ	ERRV3
	MOV	BYTE PTR [DI+1],10001100B

NOTSEG:
	AND	AL,111B
	SHL	AL,1
	SHL	AL,1
	SHL	AL,1
	OR	BYTE PTR [DI+2],AL
; ARR 2.4
; In the case of the XCHG reg,reg and TEST reg,reg we have just built the
; instruction backwards.  This is because these two instructions do not have
; the D bit.  We need to switch R/S and REG
;
; Good comment Aaron, except that we do NOT switch if a memory operand was
; present for precisely the reason that the D bit is not present
;
	CMP	BYTE PTR [TSTFLG],0
	JZ	NOSWITCH		; Not XCHG or TEST
;
; See if there is a memory operand specified.  If the MOD field is 11, then
; we do perform the exchange.
;
	MOV	AH,[DI+2]
	AND	AH,MASKMOD
	CMP	AH,MASKMOD
	JNZ	NOSWITCH
	MOV	AH,BYTE PTR [DI+2]
	AND	AH,MASKRM
	SHL	AH,1			; Low three bits to middle three
	SHL	AH,1
	SHL	AH,1
	MOV	AL,BYTE PTR [DI+2]
	AND	AL,MASKREG
	SHR	AL,1			; Middle three to low three
	SHR	AL,1
	SHR	AL,1
	OR	AL,AH			; Re combine
	AND	BYTE PTR [DI+2],MASKMOD ; Zap original
	OR	BYTE PTR [DI+2],AL	; New low 6 bits
NOSWITCH:


; SPECIAL FORM OF THE EXCHANGE COMMAND

	CMP	BYTE PTR [TSTFLG],2
	JNZ	GRPEX
	TEST	BYTE PTR [DI+1],1
	JZ	GRPEX
	PUSH	AX
	MOV	AL,BYTE PTR [DI+2]
	AND	AL,MASKMOD
	CMP	AL,MASKMOD		; MUST BE REGISTER TO REGISTER
	POP	AX
	JB	GRPEX
	OR	AL,AL
	JZ	SPECX
	MOV	AL,[DI+2]
	AND	AL,MASKRM
	JNZ	GRPEX
	MOV	CL,3
	SHR	BYTE PTR [DI+2],CL
SPECX:
	MOV	AL,[DI+2]
	AND	AL,MASKRM
	OR	AL,10010000B
	MOV	BYTE PTR [DI+1],AL
	DEC	BYTE PTR [DI]
	JMP	SHORT GRPEX

;  SECOND OPERAND WAS A MEMORY REFERENCE

GRP22:
	CMP	BYTE PTR [TSTFLG],0
	JNZ	TST2
	OR	BYTE PTR [DI+1],10B
TST2:
	MOV	AL,BYTE PTR [DI+2]
	CMP	AL,MASKMOD		; MUST BE A REGISTER
	JB	ASMERR
	CMP	BYTE PTR [SEGFLG],0
	JZ	GRP223
	AND	AL,00011000B
	JMP	SHORT GRP222
GRP223:
	AND	AL,MASKRM
	SHL	AL,1
	SHL	AL,1
	SHL	AL,1
GRP222:
	OR	AL,BYTE PTR [MODE]
	OR	AL,BYTE PTR [REGMEM]
	MOV	BYTE PTR [DI+2],AL
	MOV	AX,WORD PTR [LOWNUM]
	MOV	WORD PTR [DI+3],AX
GRPSIZ:
	MOV	BYTE PTR [DI],2
	MOV	AL,BYTE PTR [DI+2]
	AND	AL,11000111B
	CMP	AL,00000110B
	JZ	GRP24
	AND	AL,MASKMOD
	CMP	AL,01000000B
	JZ	GRP25
	CMP	AL,10000000B
	JNZ	GRPEX
GRP24:
	INC	BYTE PTR [DI]
GRP25:
	INC	BYTE PTR [DI]

GRPEX:
	CMP	BYTE PTR [MOVFLG],0
	JZ	ASSEM_EXIT

;	TEST FOR SPECIAL FORM OF MOV AX,[MEM] OR MOV [MEM],AX

	MOV	AL,[DI+1]		; GET OP-CODE
	AND	AL,11111100B
	CMP	AL,10001000B
	JNZ	ASSEM_EXIT
	CMP	BYTE PTR [DI+2],00000110B ; MEM TO AX OR AX TO MEM
	JNZ	ASSEM_EXIT
	MOV	AL,BYTE PTR [DI+1]
	AND	AL,11B
	XOR	AL,10B
	OR	AL,10100000B
	MOV	BYTE PTR [DI+1],AL
	DEC	BYTE PTR [DI]
	MOV	AX,[DI+3]
	MOV	WORD PTR [DI+2],AX

ASSEM_EXIT:
	CALL	STUFF_BYTES
	JMP	ASSEMLOOP

; Assem error. SI points to character in the input buffer
; which caused error. By subtracting from start of buffer,
; we will know how far to tab over to appear directly below
; it on the terminal. Then print "^ Error".

ASMERR:
	SUB	SI,OFFSET DG:(BYTEBUF-10) ; How many char processed so far?
	MOV	CX,SI			; Parameter for TAB in CX
	MOV	DI,OFFSET DG:ARG_BUF
	CALL	TAB			; Directly below bad char
	MOV	BYTE PTR [DI],0
	MOV	DX,OFFSET DG:SYNERR_PTR ; Error message
	CALL	PRINTF_CRLF
	JMP	ASSEMLOOP
;
;  assemble the different parts into an instruction
;
BUILDIT:
	MOV	AL,BYTE PTR [AWORD]
	OR	AL,AL
	JNZ	BUILD1
BLDERR:
	JMP	ASMERR

BUILD1:
	DEC	AL
	OR	BYTE PTR [DI+1],AL	; SET THE SIZE

BUILD2:
	CMP	BYTE PTR [NUMFLG],0	; TEST FOR IMMEDIATE DATA
	JZ	BUILD3
	CMP	BYTE PTR [MEMFLG],0
	JZ	BLDERR

BUILD3:
	MOV	AL,BYTE PTR [REGMEM]
	CMP	AL,-1
	JZ	BLD1
	TEST	AL,10000B		; TEST IF SEGMENT REGISTER
	JZ	BLD1
	CMP	BYTE PTR [MOVFLG],0
	JZ	BLDERR
	MOV	WORD PTR [DI+1],10001110B
	INC	BYTE PTR [MOVFLG]
	INC	BYTE PTR [SEGFLG]
	AND	AL,00000011B
	SHL	AL,1
	SHL	AL,1
	SHL	AL,1
	OR	AL,MASKMOD
	MOV	BYTE PTR [DI+2],AL
	RET

BLD1:
	AND	AL,00000111B
BLD4:
	OR	AL,BYTE PTR [MODE]
	OR	AL,BYTE PTR [MIDFLD]
	MOV	BYTE PTR [DI+2],AL
	MOV	AX,WORD PTR [LOWNUM]
	MOV	WORD PTR [DI+3],AX
	RET

GETREGMEM:
	MOV	BYTE PTR [F8087],0
GETREGMEM2:
	CALL	SCANP
	XOR	AX,AX
	MOV	WORD PTR [LOWNUM],AX	; OFFSET
	MOV	WORD PTR [DIFLG],AX	; DIFLG+SIFLG
	MOV	WORD PTR [BXFLG],AX	; BXFLG+BPFLG
	MOV	WORD PTR [NEGFLG],AX	; NEGFLG+NUMFLG
	MOV	WORD PTR [MEMFLG],AX	; MEMFLG+REGFLG
	DEC	AL
	CMP	BYTE PTR [F8087],0
	JZ	PUTREG
	MOV	AL,1			; DEFAULT 8087 REG IS 1
PUTREG:
	MOV	BYTE PTR [REGMEM],AL

GETLOOP:
	MOV	BYTE PTR [NEGFLG],0
GETLOOP1:
	MOV	AX,WORD PTR [SI]
	CMP	AL,','
	JZ	GOMODE
	CMP	AL,13
	JZ	GOMODE
	CMP	AL,';'
	JZ	GOMODE
	CMP	AL,9
	JZ	GETTB
	CMP	AL,' '
	JNZ	GOGET
GETTB:
	INC	SI
	JMP	GETLOOP1
GOGET:
	JMP	GETINFO

;  DETERMINE THE MODE BITS

GOMODE:
	MOV	DI,OFFSET DG:ASSEM_CNT
	MOV	BYTE PTR [MODE],11000000B
	MOV	BYTE PTR [ASSEM_CNT],2
	CMP	BYTE PTR [MEMFLG],0
	JNZ	GOMODE1
	MOV	AL,[NUMFLG]
	OR	AL,[REGFLG]
	JNZ	MORET
	OR	AL,[F8087]
	JZ	ERRET
	MOV	AL,[DI+1]
	OR	AL,[DIRFLG]
	CMP	AL,0DCH 		; ARITHMETIC?
	JNZ	MORET
	MOV	BYTE PTR [DI+1],0DEH	; ADD POP TO NULL ARG 8087
MORET:
	RET
ERRET:
	JMP	ASMERR

GOMODE1:
	MOV	BYTE PTR [MODE],0
	CMP	BYTE PTR [NUMFLG],0
	JZ	GOREGMEM

	MOV	BYTE PTR [DI],4
	MOV	AX,WORD PTR [DIFLG]
	OR	AX,WORD PTR [BXFLG]
	JNZ	GOMODE2
	MOV	BYTE PTR [REGMEM],00000110B
	RET

GOMODE2:
	MOV	BYTE PTR [MODE],10000000B
	CALL	CHKSIZ1
	CMP	CL,2
	JZ	GOREGMEM
	DEC	BYTE PTR [DI]
	MOV	BYTE PTR [MODE],01000000B

;  DETERMINE THE REG-MEM BITS

GOREGMEM:
	MOV	BX,WORD PTR [BXFLG]
	MOV	CX,WORD PTR [DIFLG]
	XOR	DX,DX
GOREG0:
	MOV	AL,BL			; BX
	ADD	AL,CH			; SI
	CMP	AL,2
	JZ	GOGO
	INC	DL
	MOV	AL,BL
	ADD	AL,CL
	CMP	AL,2
	JZ	GOGO
	INC	DL
	MOV	AL,BH
	ADD	AL,CH
	CMP	AL,2
	JZ	GOGO
	INC	DL
	MOV	AL,BH
	ADD	AL,CL
	CMP	AL,2
	JZ	GOGO
	INC	DL
	OR	CH,CH
	JNZ	GOGO
	INC	DL
	OR	CL,CL
	JNZ	GOGO
	INC	DL			; BP+DISP
	OR	BH,BH
	JZ	GOREG1
	CMP	BYTE PTR [MODE],0
	JNZ	GOGO
	MOV	BYTE PTR [MODE],01000000B
	INC	BYTE PTR [DI]
	DEC	DL
GOREG1:
	INC	DL			; BX+DISP
GOGO:
	MOV	BYTE PTR [REGMEM],DL
	RET

GETINFO:
	CMP	AX,'EN'                 ; NEAR
	JNZ	GETREG3
GETREG0:
	MOV	DL,2
GETRG01:
	CALL	SETSIZ1
GETREG1:
	CALL	SCANS
	MOV	AX,WORD PTR [SI]
	CMP	AX,"TP"                 ; PTR
	JZ	GETREG1
	JMP	GETLOOP

GETREG3:
	MOV	CX,5
	MOV	DI,OFFSET DG:SIZ8
	CALL	CHKREG			; LOOK FOR BYTE, WORD, DWORD, ETC.
	JZ	GETREG41
	INC	AL
	MOV	DL,AL
	JMP	GETRG01

GETREG41:
	MOV	AX,[SI]
	CMP	BYTE PTR [F8087],0
	JZ	GETREG5
	CMP	AX,"TS"                 ; 8087 STACK OPERAND
	JNZ	GETREG5
	CMP	BYTE PTR [SI+2],','
	JNZ	GETREG5
	MOV	BYTE PTR [DIRFLG],0
	ADD	SI,3
	JMP	GETLOOP

GETREG5:
	CMP	AX,"HS"                 ; SHORT
	JZ	GETREG1

	CMP	AX,"AF"                 ; FAR
	JNZ	GETRG51
	CMP	BYTE PTR [SI+2],'R'
	JNZ	GETRG51
	ADD	SI,3
	MOV	DL,4
	JMP	GETRG01

GETRG51:
	CMP	AL,'['
	JNZ	GETREG7
GETREG6:
	INC	BYTE PTR [MEMFLG]
GETREGADD:
	INC	SI
	JMP	GETLOOP

GETREG7:
	CMP	AL,']'
	JZ	GETREG6
	CMP	AL,'.'
	JZ	GETREG6
	CMP	AL,'+'
	JZ	GETREGAdd
	CMP	AL,'-'
	JNZ	GETREG8
	INC	BYTE PTR [NEGFLG]
	INC	SI
	JMP	GETLOOP1

GETREG8:				; LOOK FOR A REGISTER
	CMP	BYTE PTR [F8087],0
	JZ	GETREGREG
	CMP	AX,"TS"
	JNZ	GETREGREG
	CMP	BYTE PTR [SI+2],'('
	JNZ	GETREGREG
	CMP	BYTE PTR [SI+4],')'
	JNZ	ASMPOP
	MOV	AL,[SI+3]
	SUB	AL,'0'
	JB	ASMPOP
	CMP	AL,7
	JA	ASMPOP
	MOV	[REGMEM],AL
	INC	BYTE PTR [REGFLG]
	ADD	SI,5
	CMP	WORD PTR [SI],"S,"
	JNZ	ZLOOP
	CMP	BYTE PTR [SI+2],'T'
	JNZ	ZLOOP
	ADD	SI,3
ZLOOP:
	JMP	GETLOOP

GETREGREG:
	MOV	CX,20
	MOV	DI,OFFSET DG:REG8
	CALL	CHKREG
	JZ	GETREG12		; CX = 0 MEANS NO REGISTER
	MOV	BYTE PTR [REGMEM],AL
	INC	BYTE PTR [REGFLG]	; TELL EVERYONE WE FOUND A REG
	CMP	BYTE PTR [MEMFLG],0
	JNZ	NOSIZE
	CALL	SETSIZ
INCSI2:
	ADD	SI,2
	JMP	GETLOOP

NOSIZE:
	CMP	AL,11			; BX REGISTER?
	JNZ	GETREG9
	CMP	WORD PTR [BXFLG],0
	JZ	GETOK
ASMPOP:
	JMP	ASMERR

GETOK:
	INC	BYTE PTR [BXFLG]
	JMP	INCSI2
GETREG9:
	CMP	AL,13			; BP REGISTER?
	JNZ	GETREG10
	CMP	WORD PTR [BXFLG],0
	JNZ	ASMPOP
	INC	BYTE PTR [BPFLG]
	JMP	INCSI2
GETREG10:
	CMP	AL,14			; SI REGISTER?
	JNZ	GETREG11
	CMP	WORD PTR [DIFLG],0
	JNZ	ASMPOP
	INC	BYTE PTR [SIFLG]
	JMP	INCSI2
GETREG11:
	CMP	AL,15			; DI REGISTER?
	JNZ	ASMPOP			; *** error
	CMP	WORD PTR [DIFLG],0
	JNZ	ASMPOP
	INC	BYTE PTR [DIFLG]
	JMP	INCSI2

GETREG12:				; BETTER BE A NUMBER!
	MOV	BP,WORD PTR [ASMADD+2]
	CMP	BYTE PTR [MEMFLG],0
	JZ	GTRG121
GTRG119:
	MOV	CX,4
GTRG120:
	CALL	GETHX
	JMP	SHORT GTRG122
GTRG121:
	MOV	CX,2
	CMP	BYTE PTR [AWORD],1
	JZ	GTRG120
	CMP	BYTE PTR [AWORD],CL
	JZ	GTRG119
	CALL	GET_ADDRESS
GTRG122:
	JC	ASMPOP
	MOV	[HINUM],AX
	CMP	BYTE PTR [NEGFLG],0
	JZ	GETREG13
	NEG	DX
GETREG13:
	ADD	WORD PTR [LOWNUM],DX
	INC	BYTE PTR [NUMFLG]
GETLOOPV:
	JMP	GETLOOP

CHKREG:
	PUSH	CX
	INC	CX
	REPNZ	SCASW
	POP	AX
	SUB	AX,CX
	OR	CX,CX
	RET

STUFF_BYTES:
	PUSH	SI
	LES	DI,DWORD PTR ASMADD
	MOV	SI,OFFSET DG:ASSEM_CNT
	XOR	AX,AX
	LODSB
	MOV	CX,AX
	JCXZ	STUFFRET
	REP	MOVSB
	MOV	WORD PTR [ASMADD],DI
STUFFRET:
	POP	SI
	RET

SETSIZ:
	MOV	DL,1
	TEST	AL,11000B		; 16 BIT OR SEGMENT REGISTER?
	JZ	SETSIZ1
	INC	DL
SETSIZ1:
	CMP	BYTE PTR [AWORD],0
	JZ	SETSIZ2
	CMP	BYTE PTR [AWORD],DL
	JZ	SETSIZ2
SETERR:
	POP	DX
	JMP	ASMPOP
SETSIZ2:
	MOV	BYTE PTR [AWORD],DL
	RET

;  DETERMINE IF NUMBER IN AX:DX IS 8 BITS, 16 BITS, OR 32 BITS

CHKSIZ:
	MOV	CL,4
	CMP	AX,BP
	JNZ	RETCHK
CHKSIZ1:
	MOV	CL,2
	MOV	AX,DX
	CBW
	CMP	AX,DX
	JNZ	RETCHK
	DEC	CL
RETCHK:
	RET

;  get first character after first space

SCANS:
	CMP	BYTE PTR [SI],13
	JZ	RETCHK
	CMP	BYTE PTR [SI],'['
	JZ	RETCHK
	LODSB
	CMP	AL,' '
	JZ	SCANBV
	CMP	AL,9
	JNZ	SCANS
SCANBV:
	JMP	SCANB

; Set up for 8087 op-codes

SETMID:
	MOV	BYTE PTR [ASSEM1],0D8H
	MOV	AH,AL
	AND	AL,111B 		; SET MIDDLE BITS OF SECOND BYTE
	SHL	AL,1
	SHL	AL,1
	SHL	AL,1
	MOV	[MIDFLD],AL
	MOV	AL,AH			; SET LOWER BITS OF FIRST BYTE
	SHR	AL,1
	SHR	AL,1
	SHR	AL,1
	OR	[ASSEM1],AL
	MOV	BYTE PTR [F8087],1	; INDICATE 8087 OPERAND
	MOV	BYTE PTR [DIRFLG],100B
	RET

; Set MF bits for 8087 op-codes

SETMF:
	MOV	AL,[AWORD]
	TEST	BYTE PTR [DI+1],10B
	JNZ	SETMFI
	AND	BYTE PTR [DI+1],11111001B ; CLEAR MF BITS
	CMP	AL,3			; DWORD?
	JZ	SETMFRET
	CMP	AL,4			; QWORD?
	JZ	SETMFRET2
	TEST	BYTE PTR [DI+1],1
	JZ	SETMFERR
	CMP	AL,5			; TBYTE?
	JZ	SETMFRET3
	JMP	SHORT SETMFERR

SETMFI:
	CMP	AL,3			; DWORD?
	JZ	SETMFRET
	CMP	AL,2			; WORD?
	JZ	SETMFRET2
	TEST	BYTE PTR [DI+1],1
	JZ	SETMFERR
	CMP	AL,4			; QWORD?
	JNZ	SETMFERR
	OR	BYTE PTR [DI+1],111B
SETMFRET3:
	OR	BYTE PTR [DI+1],011B
	OR	BYTE PTR [DI+2],101000B
	JMP	SHORT SETMFRET
SETMFRET2:
	OR	BYTE PTR [DI+1],100B
SETMFRET:
	RET

SETMFERR:
	JMP	ASMPOP


DW_OPER:
	MOV	BP,1
	JMP	SHORT DBEN

DB_OPER:
	XOR	BP,BP
DBEN:
	MOV	DI,OFFSET DG:ASSEM_CNT
	DEC	BYTE PTR [DI]
	INC	DI
DB0:
	XOR	BL,BL
	CALL	SCANP
	JNZ	DB1
DBEX:
	JMP	ASSEM_EXIT
DB1:
	OR	BL,BL
	JNZ	DB3
	MOV	BH,BYTE PTR [SI]
	CMP	BH,"'"
	JZ	DB2
	CMP	BH,'"'
	JNZ	DB4
DB2:
	INC	SI
	INC	BL
DB3:
	LODSB
	CMP	AL,13
	JZ	DBEX
	CMP	AL,BH
	JZ	DB0
	STOSB
	INC	BYTE PTR [ASSEM_CNT]
	JMP	DB3
DB4:
	MOV	CX,2
	CMP	BP,0
	JZ	DB41
	MOV	CL,4
DB41:
	PUSH	BX
	CALL	GETHX
	POP	BX
	JNC	DB5
	JMP	ASMERR
DB5:
	MOV	AX,DX
	CMP	BP,0
	JZ	DB6
	STOSW
	INC	BYTE PTR [ASSEM_CNT]
	JMP	SHORT DB7
DB6:
	STOSB
DB7:
	INC	BYTE PTR [ASSEM_CNT]
	JMP	DB0

; ORG pseudo op

DOORG:
	MOV	BP,WORD PTR ASMADD+2
	CALL	GET_ADDRESS
	MOV	WORD PTR ASMADD,DX
	MOV	WORD PTR ASMADD+2,AX
	JMP	ASSEMLOOP

CODE	ENDS
	END	ASSEM
